package com.ruoyi.asset.common.scopecode.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.asset.common.scopecode.constant.ServiceCode;
import com.ruoyi.asset.common.scopecode.domain.ScopeCode;
import com.ruoyi.asset.common.scopecode.exception.ScopeCodeException;
import com.ruoyi.asset.common.scopecode.mapper.ScopeCodeMapper;
import com.ruoyi.asset.common.scopecode.service.IScopeCodeService;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.redis.CacheUtils;
import com.ruoyi.common.utils.redis.RedisUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class ScopeCodeService implements IScopeCodeService {
	private final ScopeCodeMapper baseMapper;
	private final static int SCOPE_CODE_INCREASEBY = 50;
	private final static String REDIS_GROUP_ASSET = "asset";

	@Override
	public String getNextScopeCode(ServiceCode serviceCode, String maintenanceType, String maintenanceTypeLabel)
			throws ScopeCodeException {
		if (StringUtils.isBlank(maintenanceType)) {
			throw new ScopeCodeException("管理类型不能为空");
		}

		maintenanceType = StringUtils.leftPad(maintenanceType, 2, "0");

		RLock rLock = null;
		String scopeCodeSuffix = null;
		try {
			String redisKey = "scopeCode:" + serviceCode.getScopeCodePrefix() + maintenanceType;

			// 加锁
			int times = 0;
			while (rLock == null && times <= 10) {
				rLock = RedisUtils.getClient().getLock(redisKey);

				try {
					if (rLock == null) {
						Thread.sleep(10);
					}
				} catch (Exception e) {
					System.out.println(e.getMessage());
				}
				times++;
			}

			if (rLock == null) {
				throw new ScopeCodeException("获取范围编码失败，失败原因：获取分布式锁失败");
			}

			Object obj = CacheUtils.get(REDIS_GROUP_ASSET, redisKey);
			if (obj != null) {
			   scopeCodeSuffix = obj.toString();
			}

			ScopeCode scopeCode = null;
			if (StringUtils.isBlank(scopeCodeSuffix)) {
				// 如果缓存中没有数据，则从数据库获取
				scopeCode = select(serviceCode, maintenanceType);

				if (scopeCode == null) {
					// 插入
					insert(serviceCode, maintenanceType, maintenanceTypeLabel);
					scopeCodeSuffix = "1";
				} else {
					scopeCodeSuffix = Integer.toString(scopeCode.getNextId());
				}
			} 
			
			if ((Integer.valueOf(scopeCodeSuffix) % SCOPE_CODE_INCREASEBY) == 0) {
				// 如果当前值是50的整数倍则修改数据库中的值
				if (scopeCode == null) {
				    scopeCode = select(serviceCode, maintenanceType);
				}
				
				scopeCode.setNextId(scopeCode.getNextId() + SCOPE_CODE_INCREASEBY);
				baseMapper.updateById(scopeCode);
			}

			// 缓存中的值加1
			int nextScopeCodeValue = Integer.valueOf(scopeCodeSuffix) + 1;
			CacheUtils.put(REDIS_GROUP_ASSET, redisKey, nextScopeCodeValue);
		} finally {
			if (rLock != null) {
				// 释放锁
				rLock.forceUnlock();
			}
		}

		return serviceCode.getScopeCodePrefix() + maintenanceType + StringUtils.leftPad(scopeCodeSuffix, 6, "0");
	}

	private void insert(ServiceCode serviceCode, String maintenanceType, String maintenanceTypeLabel) {
		ScopeCode scopeCode = new ScopeCode();

		BeanCopyUtils.copy(serviceCode, scopeCode);
		scopeCode.setMaintenanceType(maintenanceType);
		scopeCode.setMaintenanceTypeLabel(maintenanceTypeLabel);
		scopeCode.setNextId(SCOPE_CODE_INCREASEBY);

		baseMapper.insert(scopeCode);
	}

	private ScopeCode select(ServiceCode serviceCode, String maintenanceType) {
		LambdaQueryWrapper<ScopeCode> lqw = Wrappers.lambdaQuery();

		lqw.eq(ScopeCode::getServiceCode, serviceCode.getServiceCode());
		lqw.eq(ScopeCode::getMaintenanceType, maintenanceType);

		ScopeCode scopeCode = baseMapper.selectOne(lqw);

		return scopeCode;
	}
}
